import json
import logging

import const
from singleton import singleton
import sqlalchemy
from sqlalchemy.orm import sessionmaker
from nodes import *


# new_node attributes
@singleton
class DB:
    def __init__(self, config_path):
        with open(config_path, 'r') as f:
            dbconfig = json.load(f)
            self.engine_url = "mysql+pymysql://{}:{}@{}:{}/{}".format(dbconfig['user'], dbconfig['password'],
                                                                      dbconfig['host'],
                                                                      dbconfig['port'], dbconfig['database'])
            self.engine = sqlalchemy.create_engine(self.engine_url, echo=True)
            session = sessionmaker(bind=self.engine)
            self.session = session()


class Node:
    def __init__(self):
        self.name = ""
        self.type = ""
        self.jump_node = ""
        self.retry_node = ""
        self.fail_node = ""

    def check_node_params(self):
        logging.info("[fsm: battle] checking node params, name: {}, type: {}, jump_node: {}, retry_node: {}, "
                     "fail_node: {}".format(self.name, self.type, self.jump_node, self.retry_node, self.fail_node))
        if self.type == const.NORMAL_NODE:
            if self.name == "" or self.jump_node == "" or self.retry_node == "" or self.fail_node == "":
                raise Exception("[fsm: checkNodeParams] normal new_node params error, new_node's name's ", self.name)
        elif self.type == const.FINAL_NODE:
            if self.name == "" or self.jump_node != "" or self.retry_node != "" or self.fail_node != "":
                raise Exception("[fsm: checkNodeParams] final new_node params error, new_node's name's empty")
        elif self.type == const.START_NODE:
            if self.name == "" or self.jump_node == "" or self.retry_node == "" or self.fail_node == "":
                raise Exception("[fsm: checkNodeParams] start new_node params error, new_node's name's ", self.name)
        else:
            raise Exception("[fsm: checkNodeParams] new_node type error, new_node's type's ", self.type)


@singleton
class Config:
    def __init__(self):
        self.nodes = []
        self.max_workers = -1
        self.node_info = {}

    def check_config_params(self):
        final_node_count = 0
        start_node_count = 0
        for registered_node in self.nodes:
            try:
                registered_node.check_node_params()
            except Exception as e:
                logging.error("[fsm: checkConfigParams] check node params error, {}".format(e))
                exit(1)
            if registered_node.type == const.FINAL_NODE:
                final_node_count += 1
            if registered_node.type == const.START_NODE:
                start_node_count += 1
            self.node_info[registered_node.name] = registered_node
            if registered_node.type != const.FINAL_NODE:
                logging.info("[fsm: checkConfigParams] node {} is registered, jump node {}, retry node {}, fail node {}"
                             .format(registered_node.name, registered_node.jump_node, registered_node.retry_node,
                                     registered_node.fail_node))
            else:
                logging.info("[fsm: checkConfigParams] node {} is registered"
                             .format(registered_node.name))
        if final_node_count != 1:
            raise Exception("[fsm: check_config_params] two or more final registered_node set, final registered_node "
                            "count is ", final_node_count)
        if start_node_count != 1:
            raise Exception("[fsm: check_config_params] two or more start registered_node set, start registered_node "
                            "count is ", start_node_count)
        if self.max_workers == -1:
            raise Exception("[fsm: check_config_params] max_workers is invalid, forgot to set a value?")
